﻿using EntityFrameworkETL.Interceptors;
using EntityFrameworkETL.Interfaces;
using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Data.Entity;
using System.Data.Entity.Infrastructure.Interception;
using System.Linq;
using System.Text;
using EntityFramework.Extensions;
using System.Data.Entity;
namespace EntityFrameworkETL
{
    public class Repository : IRepository
    {
        public Repository(Func<DbContext> sourceContextFunction, Func<DbContext> destinationContextFunction)
        {
            SourceContextFunction = sourceContextFunction;
            DestinationContextFunction = destinationContextFunction;
        }

        public Func<DbContext> SourceContextFunction { get; set; }
        public Func<DbContext> DestinationContextFunction { get; set; }

        public IEnumerable<T> SelectSource<T>(Func<IQueryable<T>, IQueryable<T>> query) where T : class
        {
            using (var context = SourceContextFunction())
            {
                IQueryable<T> qry = context.Set<T>().AsNoTracking();
                if (query!=null)
                    qry = query(qry);
                return qry.ToList();
            }
        }

        public IEnumerable<DbCommand> GetInsertCommands<T>(IEnumerable<T> items, bool identityInsert) where T : class
        {
            List<DbCommand> results = new List<DbCommand>();
            IDbCommandInterceptor interceptor;
            if (identityInsert)
                interceptor = new IdentityInsertCommandCacheInterceptor(x => results.Add(x));
            else
                interceptor = new NonIdentityInsertCommandCacheInterceptor(x => results.Add(x));
            DbInterception.Add(interceptor);
            using (var context = DestinationContextFunction())
            {
                context.Configuration.AutoDetectChangesEnabled = false;
                foreach (var item in items)
                {
                    context.Set<T>().Add(item);
                }
                context.SaveChanges();
            }
            DbInterception.Remove(interceptor);
            return results;
        }

        public string DestinationConnectionString()
        {
            using (var context = DestinationContextFunction())
            {
                return context.Database.Connection.ConnectionString;
            }
        }

        public IEnumerable<DbCommand> GetDeleteCommands<T>(IEnumerable<T> items) where T : class
        {
            List<DbCommand> results = new List<DbCommand>();
            var interceptor = new NonIdentityInsertCommandCacheInterceptor(x=>results.Add(x));
            DbInterception.Add(interceptor);
            using (var context = DestinationContextFunction())
            {
                context.Configuration.AutoDetectChangesEnabled = false;
                foreach (var item in items)
                {
                    context.Set<T>().Attach(item);
                    context.Set<T>().Remove(item);
                }
                context.SaveChanges();
            }
            DbInterception.Remove(interceptor);
            return results;
        }

        public IEnumerable<T> SelectDestinationForDelete<T>() where T : class
        {
            using (var context = DestinationContextFunction())
            {
                return context.Set<T>().AsNoTracking().ToList();
            }
        }

        public void DeleteAll<T>() where T : class
        {
            using (var context = DestinationContextFunction())
            {
                List<string> strings = new List<string>();
                context.Set<T>().AsQueryable().Delete();
            }
        }
        public bool IdentityInsert { get; set; }
    }
}
